// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: chensili

#pragma once

#include <memory>
#include <optional>
#include <string>

#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/base/symbology/util.h"
#include "coin2/exchange/quoinex/symbology/currency.h"

namespace coin2::exchange::quoinex::symbology {

class QuoinexProduct : public base::symbology::SpotProduct<QuoinexCurrency, QuoinexProduct>,
                       public base::symbology::ProductFromStrMixin<QuoinexProduct> {
 public:
  typedef SpotProduct<QuoinexCurrency, QuoinexProduct> BaseProduct;

  QuoinexProduct(const QuoinexCurrency& base, const QuoinexCurrency& quote)
      : SpotProduct(
            base,
            quote,
            ToQuoinexNativeProduct(base, quote),
            ToQuoinexNativeProduct(base, quote),
            base::market::ExchangeType::Quoinex) {}

 public:
  static std::unique_ptr<QuoinexProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    std::unique_ptr<QuoinexCurrency> base_ptr;
    std::unique_ptr<QuoinexCurrency> quote_ptr;
    bool success =
        ParseQuoinexNativeProduct(native_product, resolve_timestamp, &base_ptr, &quote_ptr);
    if (success) {
      return std::make_unique<QuoinexProduct>(*base_ptr, *quote_ptr);
    } else {
      return {};
    }
  }

 private:
  static bool ParseQuoinexNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp,
      std::unique_ptr<QuoinexCurrency>* base_ptr,
      std::unique_ptr<QuoinexCurrency>* quote_ptr) {
    const std::string& product_str_upper = StringToUpperCopy(product_str);
    if (product_str_upper == "TMTGUSD") {
      *base_ptr = QuoinexCurrency::FromNormStrNoThrow("TMTG", resolve_timestamp);
      *quote_ptr = QuoinexCurrency::FromNormStrNoThrow("USD", resolve_timestamp);
      return true;
    } else if (product_str_upper == "USDXSGD") {
      *base_ptr = QuoinexCurrency::FromNormStrNoThrow("USD", resolve_timestamp);
      *quote_ptr = QuoinexCurrency::FromNormStrNoThrow("XSGD", resolve_timestamp);
      return true;
    } else {


    static const std::string quotes[] = {
      "ANCT", "ARST", "AUD", "BCH", "BRLT",
      "BTC", "CNY", "DAI", "ETH", "EUR",
      "GUSD", "GYEN", "HKD", "IDRT", "INR",
      "JPY", "PHP", "QASH", "SGD", "TRYB",
      "USDC", "USDT", "XDC", "XIDR", "XRP",
      "ZUSD", "IDR", "USD"
    };
    for (const auto& quote_cand : quotes) {
      if (StringEndsWith(product_str_upper, quote_cand)) {
        size_t base_len = product_str_upper.size() - quote_cand.size();
        std::string base = product_str_upper.substr(0, base_len);
        *base_ptr = QuoinexCurrency::FromNormStrNoThrow(base, resolve_timestamp);
        *quote_ptr = QuoinexCurrency::FromNormStrNoThrow(quote_cand, resolve_timestamp);
        return true;
      }
    }
    return false;
  }
 }
  static std::string ToQuoinexNativeProduct(
      const QuoinexCurrency& base,
      const QuoinexCurrency& quote) {
    using base::market::MarketType;
    std::stringstream ss;
    ss << base.native_currency(MarketType::Spot) <<
        quote.native_currency(MarketType::Spot);
    return StringToLowerCopy(ss.str());
  }
};

}  // namespace coin2::exchange::quoinex::symbology
